[NET] front: Fix tx buffer leak in teardown path. Fix rx-buffer
authorkaf24@localhost.localdomain <kaf24@localhost.localdomain>
Sat, 19 Aug 2006 10:08:40 +0000 (11:08 +0100)
committerkaf24@localhost.localdomain <kaf24@localhost.localdomain>
Sat, 19 Aug 2006 10:08:40 +0000 (11:08 +0100)
cleanup: cannot free skbuffs until their memory is remapped by
multicall.
Signed-off-by: Keir Fraser <keir@xensource.com>
linux-2.6-xen-sparse/drivers/xen/netfront/netfront.c

index 039a2a6bcb9c43cc6fd1df231616e23653c045f1..5625caa9afe324d0339f90933be7b4150a5cedff 100644 (file)
@@ -1397,10 +1397,31 @@ err:
        return more_to_do;
 }
 
+static void netif_release_tx_bufs(struct netfront_info *np)
+{
+       struct sk_buff *skb;
+       int i;
+
+       for (i = 1; i <= NET_TX_RING_SIZE; i++) {
+               if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
+                       continue;
+
+               skb = np->tx_skbs[i];
+               gnttab_end_foreign_access_ref(
+                       np->grant_tx_ref[i], GNTMAP_readonly);
+               gnttab_release_grant_reference(
+                       &np->gref_tx_head, np->grant_tx_ref[i]);
+               np->grant_tx_ref[i] = GRANT_INVALID_REF;
+               add_id_to_freelist(np->tx_skbs, i);
+               dev_kfree_skb_irq(skb);
+       }
+}
+
 static void netif_release_rx_bufs(struct netfront_info *np)
 {
        struct mmu_update      *mmu = np->rx_mmu;
        struct multicall_entry *mcl = np->rx_mcl;
+       struct sk_buff_head free_list;
        struct sk_buff *skb;
        unsigned long mfn;
        int xfer = 0, noxfer = 0, unused = 0;
@@ -1411,6 +1432,8 @@ static void netif_release_rx_bufs(struct netfront_info *np)
                return;
        }
 
+       skb_queue_head_init(&free_list);
+
        spin_lock(&np->rx_lock);
 
        for (id = 0; id < NET_RX_RING_SIZE; id++) {
@@ -1451,7 +1474,7 @@ static void netif_release_rx_bufs(struct netfront_info *np)
 
                        set_phys_to_machine(pfn, mfn);
                }
-               dev_kfree_skb(skb);
+               __skb_queue_tail(&free_list, skb);
                xfer++;
        }
 
@@ -1474,6 +1497,9 @@ static void netif_release_rx_bufs(struct netfront_info *np)
                }
        }
 
+       while ((skb = __skb_dequeue(&free_list)) != NULL)
+               dev_kfree_skb(skb);
+
        spin_unlock(&np->rx_lock);
 }
 
@@ -1573,19 +1599,7 @@ static void network_connect(struct net_device *dev)
         */
 
        /* Step 1: Discard all pending TX packet fragments. */
-       for (requeue_idx = 0, i = 1; i <= NET_TX_RING_SIZE; i++) {
-               if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
-                       continue;
-
-               skb = np->tx_skbs[i];
-               gnttab_end_foreign_access_ref(
-                       np->grant_tx_ref[i], GNTMAP_readonly);
-               gnttab_release_grant_reference(
-                       &np->gref_tx_head, np->grant_tx_ref[i]);
-               np->grant_tx_ref[i] = GRANT_INVALID_REF;
-               add_id_to_freelist(np->tx_skbs, i);
-               dev_kfree_skb_irq(skb);
-       }
+       netif_release_tx_bufs(np);
 
        /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
        for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
@@ -1632,6 +1646,7 @@ static void network_connect(struct net_device *dev)
 static void netif_uninit(struct net_device *dev)
 {
        struct netfront_info *np = netdev_priv(dev);
+       netif_release_tx_bufs(np);
        netif_release_rx_bufs(np);
        gnttab_free_grant_references(np->gref_tx_head);
        gnttab_free_grant_references(np->gref_rx_head);